/*!
\copyright  Copyright (c) 2023-2025 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file       headset_lea_src.c
\brief      Speaker LE Source audio interface functionality implementation.

*/

#ifdef INCLUDE_LE_AUDIO_BROADCAST_SOURCE

#include "unexpected_message.h"
#include "audio_sources.h"
#include <kymera_adaptation_audio_protected.h>

#include "headset_lea_src.h"
#include "headset_lea_src_config.h"
#include "headset_sm.h"
#include "le_audio_client.h"
#include "le_audio_client_context.h"


#include <device_types.h>
#include <ui.h>
#include <panic.h>
#include <local_addr.h>
#include <stdio.h>

/*! LEA broadcast params for different audio sources supported for broadcast.
 *  Add the configuration for specific audio source if default config is not used. */
le_media_config_t lea_broadcast_params[MAX_LEA_BROADCAST_CONFIG_TYPES] =
{
    [DEFAULT_LEA_BROADCAST_CONFIG] =
    {
        .sample_rate = 48000,
        .frame_length = HEADSET_LEA_CONFIG_BROADCAST_DEFAULT_SDU_SIZE,
        .frame_duration = HEADSET_LEA_CONFIG_BROADCAST_DEFAULT_SDU_INTERVAL,
        .stream_type = KYMERA_LE_STREAM_DUAL_MONO,
        .presentation_delay = HEADSET_LEA_CONFIG_BROADCAST_DEFAULT_PRESENTATION_DELAY,
        .codec_type = KYMERA_LE_AUDIO_CODEC_LC3,
        .codec_id = {
                        .codingFormat = PACS_LC3_CODEC_ID,
                        .companyId = 0,
                        .vendorSpecificCodecId = 0,
                    },
        .codec_frame_blocks_per_sdu = HEADSET_LEA_CONFIG_BROADCAST_DEFAULT_MAX_CODEC_PER_SDU,
        .transport_latency_big = HEADSET_LEA_CONFIG_BROADCAST_DEFAULT_TRANSPORT_LATENCY,
    },

    [UNICAST_SOURCE_LEA_BROADCAST_CONFIG] =
    {
        .sample_rate = 48000,
        .frame_length = HEADSET_LEA_CONFIG_UNICAST_BROADCAST_SDU_SIZE,
        .frame_duration = HEADSET_LEA_CONFIG_UNICAST_BROADCAST_SDU_INTERVAL,
        .stream_type = KYMERA_LE_STREAM_DUAL_MONO,
        .presentation_delay = HEADSET_LEA_CONFIG_UNICAST_BROADCAST_PRESENTATION_DELAY,
        .codec_type = KYMERA_LE_AUDIO_CODEC_LC3,
        .codec_id = {
                        .codingFormat = PACS_LC3_CODEC_ID,
                        .companyId = 0,
                        .vendorSpecificCodecId = 0,
                    },
        .codec_frame_blocks_per_sdu = HEADSET_LEA_CONFIG_BROADCAST_DEFAULT_MAX_CODEC_PER_SDU,
        .transport_latency_big = HEADSET_LEA_CONFIG_UNICAST_BROADCAST_TRANSPORT_LATENCY,
    },
};

/*! LEA broadcast params info */
const appKymeraLeAudioBroadcastParamsInfo lea_broadcast_params_info[] =
{
  /* audio source type, LEA brodcast params for corresponding audio source */
  { KYMERA_AUDIO_SOURCE_A2DP, &lea_broadcast_params[DEFAULT_LEA_BROADCAST_CONFIG] },
  { KYMERA_AUDIO_SOURCE_LE_AUDIO_UNICAST, &lea_broadcast_params[UNICAST_SOURCE_LEA_BROADCAST_CONFIG] },
  { KYMERA_AUDIO_SOURCE_LINE_IN, &lea_broadcast_params[DEFAULT_LEA_BROADCAST_CONFIG] },
  { KYMERA_AUDIO_SOURCE_USB, &lea_broadcast_params[DEFAULT_LEA_BROADCAST_CONFIG] },
};

/*! LEA broadcast params table used to obatin corresponding config based on the audio source type */
static const appKymeraLeAudioBroadcastParamsTable lea_broadcast_params_table =
{
    .broadcast_params_table = lea_broadcast_params_info,
    .table_length = ARRAY_DIM(lea_broadcast_params_info)
};

TaskData headsetLeaSrc_taskData;

/*! Task handler to receiver the LE Audio client messages */
static void headsetLeaSrc_HandleMessage(Task task, MessageId id, Message message);
/*! To update the LEA broadcast params based on the current & previous audio source */
static void headsetLeaSrc_UpdateLeaBroadcastParams(appKymeraLeAudioMediaSenderSourceType current_audio_source_type,
                                                   appKymeraLeAudioMediaSenderSourceType prev_audio_source_type);
/*! To handle the reconfiguration of broadcast source when the audio source is changed */
static void headsetLeaSrc_HandleBroadcastSourceReconfiguration(void);

static const kymera_lea_broadcast_config_callback_interface_t headset_lea_broadcast_config_interface =
{
    .Kymera_UpdateLeaBroadcastParams = headsetLeaSrc_UpdateLeaBroadcastParams,
    .Kymera_HandleBroadcastSourceReconfiguration = headsetLeaSrc_HandleBroadcastSourceReconfiguration,
};

static void headsetLeaSrc_UpdateLeaBroadcastParams(appKymeraLeAudioMediaSenderSourceType current_audio_source_type,
                                                   appKymeraLeAudioMediaSenderSourceType prev_audio_source_type)
{
    DEBUG_LOG("headsetLeaSrc_UpdateLeaBroadcastParams,"
              "current_audio_source = enum:appKymeraLeAudioMediaSenderSourceType:%d,"
              "prev_audio_source_type = enum:appKymeraLeAudioMediaSenderSourceType:%d",
              current_audio_source_type, prev_audio_source_type);
    if (prev_audio_source_type != KYMERA_AUDIO_SOURCE_NONE)
    {
        if (Kymera_GetLeAudioBroadcastRole() == KYMERA_LE_AUDIO_BROADCASTER &&
                LeAudioClient_IsBroadcastSourceStreamingActive())
        {
            Kymera_InternalDisableLeaBroadcastForReconfiguration();
            LeAudioClient_StopStreaming(INVALID_GROUP_HANDLE, FALSE);
            Kymera_SetBroadcastSourceReconfigurationStatus(TRUE);
        }
        LeAudioClientBroadcast_BroadcastConfigChanged();
    }
    HeadsetLeaSrcConfig_UpdateBroadcastConfig(current_audio_source_type);
}

static void headsetLeaSrc_HandleBroadcastSourceReconfiguration(void)
{
    DEBUG_LOG("headsetLeaSrc_HandleBroadcastSourceReconfiguration");
    if (Kymera_GetBroadcastSourceReconfigurationStatus() &&
            Kymera_GetLeAudioBroadcastRole() == KYMERA_LE_AUDIO_BROADCASTER &&
            !LeAudioClient_IsBroadcastSourceStreamingActive() &&
            AudioSources_GetRoutedSource() != audio_source_none)
    {
        Kymera_SetBroadcastSourceReconfigurationStatus(FALSE);
        /* Enable broadcast if disabled internally for config update only
         * after previous broadcast session is stopped and audio is active */
        HeadsetLeaSrc_AudioStart();
    }
}

static void headsetLeaSrc_HandleStreamConnected(LE_AUDIO_CLIENT_STREAM_START_IND_T *msg)
{
    if(msg->status != LE_AUDIO_CLIENT_STATUS_SUCCESS)
    {
        DEBUG_LOG_ERROR("headsetLeaSrc_HandleStreamConnected, stream start failed");
        return;
    }
    Kymera_EnableLeaBroadcasting(TRUE);
}

static void headsetLeaSrc_HandleStreamDisconnected(LE_AUDIO_CLIENT_STREAM_STOP_IND_T *msg)
{
    UNUSED(msg);
    DEBUG_LOG_FN_ENTRY("headsetLeaSrc_HandleStreamDisconnected");

    /* Handle reconfiguration of broadcast source if necessary when audio source is changed */
    headsetLeaSrc_HandleBroadcastSourceReconfiguration();
}

static void headsetLeaSrc_HandleMessage(Task task, MessageId id, Message message)
{
    UNUSED(task);

    DEBUG_LOG_FN_ENTRY("headsetLeaSrc_HandleMessage %d", id);

    switch (id)
    {
        case LE_AUDIO_CLIENT_STREAM_START_IND:
            headsetLeaSrc_HandleStreamConnected((LE_AUDIO_CLIENT_STREAM_START_IND_T *) message);
            break;

        case LE_AUDIO_CLIENT_STREAM_STOP_IND:
            headsetLeaSrc_HandleStreamDisconnected((LE_AUDIO_CLIENT_STREAM_STOP_IND_T *) message);
            break;

        default:
            UnexpectedMessage_HandleMessage(id);
            break;

    }
}

/* Used to start broadcast */
void HeadsetLeaSrc_AudioStart(void)
{
    /* Group handle is not required for Broadcasting, just context media is required */
    LeAudioClient_StartStreaming(INVALID_GROUP_HANDLE, CAP_CLIENT_CONTEXT_TYPE_MEDIA);
}

/* Used to stop broadcast */
void HeadsetLeaSrc_AudioStop(void)
{
    Kymera_EnableLeaBroadcasting(FALSE);
    /* Both group handle and removing config is not required for stopping broadcast */
    LeAudioClient_StopStreaming(INVALID_GROUP_HANDLE, FALSE);
}

bool HeadsetLeaSrc_Init(void)
{
    DEBUG_LOG_FN_ENTRY("Headset_LeaInit");

    headsetLeaSrc_taskData.handler = headsetLeaSrc_HandleMessage;
    LeAudioClient_ClientRegister(&headsetLeaSrc_taskData);
    HeadsetLeaSrcConfig_Init();
    LeAudioClient_SetMode(LE_AUDIO_CLIENT_MODE_BROADCAST);
    HeadsetLeaSrcConfig_SetPbpBroadcastmode(FALSE);
    Kymera_RegisterLeaBroadcastConfigCallbackInterface(&headset_lea_broadcast_config_interface);
    Kymera_InitializeLeaBroacastParams(&lea_broadcast_params_table);

    return TRUE;
}

#endif  /* INCLUDE_LE_AUDIO_BROADCAST_SOURCE */
